import numpy
from .utils    import parse_indices
from .variable import Variable, SubspaceVariable

# ====================================================================
#
# Coordinate object
#
# ====================================================================

class Coordinate(Variable):
    '''

A CF dimension or auxiliary coordinate construct.

The coordinate array's bounds (if present) are stored in the `bounds`
attribute. The `climatology` CF property indicates if the bounds are
intervals of climatological time.

If the coordinate is connected to one or more transform constructs
then pointers to the transformations are stored in the `transforms`
attribute.

'''

    _special_attributes = Variable._special_attributes.union(set(('bounds',
                                                                  'climatology',
                                                                  'transforms',
                                                                  )))

    def _binary_operation(self, other, method):
        '''
'''
        self_bounds = getattr(self, 'bounds', None)

        if isinstance(other, self.__class__):
            other_bounds = getattr(other, 'bounds', None)
            if other_bounds:
                if not self_bounds:
                    raise TypeError("asdfsdfdfds 0000")
            elif self_bounds:
                raise TypeError("asdfsdfdfds 00001")

        elif isinstance(other, (float, int, long)):
            other_bounds = other

        elif isinstance(other, numpy.ndarray):
            if self_bounds:
                if other.size > 1:
                    raise TypeError("4444444")
                other_bounds = other
        #-- End: if

        new = super(Coordinate, self)._binary_operation(other, method)

        if self_bounds:
            bounds = self_bounds._binary_operation(other_bounds, method)

        inplace = method[2] == 'i'

        if not inplace:
            new.bounds = bounds
            return new
        else: 
            self.bounds = bounds
            return self
    #--- End: def

    def _get_direction(self):
        '''
    
Return True if a coordinate is increasing, otherwise return False.

A coordinate is considered to be increasing if its *raw* data array
values are increasing in index space or if it has no data not bounds
data.

If the direction can not be inferred from the coordinate's data, then
the `positive` CF property is used, if present, or the coordinate's
units.

The direction is inferred from the coordinate's data array values or
its from coordinates. It is not taken directly from its Data object.

:Returns:

    out : bool
        Whether or not the coordinate is increasing.
        
**Examples**

>>> c.array
array([  0  30  60])
>>> c._get_direction()
True
>>> c.array
array([15])
>>> c.bounds.array
array([  30  0])
>>> c._get_direction()
False

'''
        if not self.hasData:
            return True

        if self.ndim > 1:
            raise ValueError(
                "Can't find the direction of a multidimensional coordinate")
        
        c = self.Data
        
        # Infer the direction from the sign of the difference between
        # its first two elements
        if c.size > 1:
            c = c[:2].array
            return c[0] < c[1]
        #--- End: if

        # Still here? Then infer the direction from the dimension
        # coordinate's bounds, if it has any
        if self.isbounded:
            b = self.bounds.Data
            indices = (0,)*(b.ndim-1) + (slice(None),)
            b = b[indices].array[indices]
            return b[0] < b[1]
        #--- End: if

        # Still here? Then infer the direction from the dimension
        # coordinate's positive CF property, if it has one.
        if hasattr(self, 'positive'):
            if self.positive.lower().startswith('d'): # d for down
                return False
        #--- End: if

        # Still here? Then infer the direction from the units
        return not self.Units.ispressure
    #--- End: def

#    def _equivalent(self, other, transpose=None,
#                         rtol=None, atol=None):
#        '''
#
#'''        
#        identity0 = self.identity()
#        identity1 = other.identity()
#
#        if not (identity0 is not None and identity0 == identity1):
#            return False
#
#        if not super(Coordinate, self)._equivalent_data(other, 
#                                                        transpose=transpose,
#                                                        rtol=rtol, atol=atol):
#            return False
#        #--- End: if
#
#        # Compare the bounds
#        bounds       = getattr(self,  'bounds', None)
#        other_bounds = getattr(other, 'bounds', None)
#        if bounds is not None:
#            if other_bounds is None:
#                return False
#
#            if tranpose:
#               tranpose = tranpose.copy()
#               tranpose['bounds'] = 'bounds'
#            #--- End: if
#
#            return bounds._equivalent_data(other_bounds, tranpose=transpose,
#                                           rtol=rtol, atol=atol)
#
#        elif other_bounds is not None:
#            return False
#
#        # Still here? Then the data are equivalent.
#        return True
#    #--- End: def

    def _equivalent_data(self, other, transpose=None,
                         rtol=None, atol=None):
        '''

'''
        # Compare the data arrays
        if not super(Coordinate, self)._equivalent_data(other, 
                                                        transpose=transpose,
                                                        rtol=rtol, atol=atol):
            return False
        #--- End: if

        # Compare the bounds' data arrays
        bounds       = getattr(self,  'bounds', None)
        other_bounds = getattr(other, 'bounds', None)
        if bounds is not None:
            if other_bounds is None:
                return False

            if transpose:
               transpose = transpose.copy()
               transpose['bounds'] = 'bounds'
            #--- End: if

            return bounds._equivalent_data(other_bounds, transpose=transpose,
                                           rtol=rtol, atol=atol)

        elif other_bounds is not None:
            return False

        # Still here? Then the data are equivalent.
        return True
    #--- End: def

    def _set_Data_attributes(self, dimensions, directions):
        '''
        Set the metadata.    

:Parameters:

    dimensions : list

    directions : dict

:Returns:

    None

'''
        super(Coordinate, self)._set_Data_attributes(dimensions, directions)

        # ------------------------------------------------------------
        # Set the metadata for its bounds' data
        # ------------------------------------------------------------
        if self.isbounded:

            c = self.Data
            b = self.bounds.Data
    
            # Units. Give them the coordinate's units. Note that we
            # don't want to change any units set on the bounds
            b.Units = c.Units.copy()
            if not b.Units:
                b.partitions[0].Units = b.Units.copy()  # dch check
                
            # Order
            dim_name_map = dict((dim, new_dim) 
                                for dim, new_dim in zip(b.order[:-1], dimensions))
            dim_name_map[b.order[-1]] = 'bounds'
            b.change_dimension_names(dim_name_map)
     
            # Direction
            if c.isscalar:
                b.direction = {'bounds': c.direction}

            else:
                b.direction = c.direction.copy()
                if c.ndim == 1:
                    # 1-d coordinate
                    b.direction['bounds'] = c.direction[c.order[0]]
                else:
                    # N-d coordinate
                    b.direction['bounds'] = True
            #--- End: if

            for partition in b.partitions.flat():
                partition.direction = b.direction.copy()
        #--- End: if            

    #--- End: def
        
    # ----------------------------------------------------------------
    # Attribute: dtype
    # ----------------------------------------------------------------
    @property
    def dtype(self):
        '''

Numpy data-type of the data array.

**Examples**

>>> c.dtype
dtype('float64')
>>> import numpy
>>> c.dtype = numpy.dtype('float32')

'''
        if self.hasData:
            return self.Data.dtype

        if self.isbounded and hasattr(self.bounds, 'dtype'):
            return self.bounds.dtype

        raise AttributeError("%s doesn't have attribute 'dtype'" %
                             self.__class__.__name__)
    #--- End: def
    @dtype.setter
    def dtype(self, value):
        if self.hasData:
            self.Data.dtype = value

        if self.isbounded:
            self.bounds.dtype = value
    #--- End: def

    @property
    def subspace(self):
        '''

Return a new coordinate whose data and bounds are subspaced in a
consistent manner.

This attribute may be indexed to select a subspace from dimension
index values.

**Subspacing by indexing**

Subspacing by dimension indices uses an extended Python slicing
syntax, which is similar numpy array indexing. There are two
extensions to the numpy indexing functionality:

* Size 1 dimensions are never removed.

  An integer index i takes the i-th element but does not reduce the
  rank of the output array by one.

* When advanced indexing is used on more than one dimension, the
  advanced indices work independently.

  When more than one dimension's slice is a 1-d boolean array or 1-d
  sequence of integers, then these indices work independently along
  each dimension (similar to the way vector subscripts work in
  Fortran), rather than by their elements.

**Examples**

'''
        return SubspaceCoordinate(self)
    #--- End: def

    # ----------------------------------------------------------------
    # Attribute: Units
    # ----------------------------------------------------------------
    @property
    def Units(self):
        '''
The Units object containing the units of the data array.

'''
        return Variable.Units.fget(self)
    #--- End: def

    @Units.setter
    def Units(self, value):
        Variable.Units.fset(self, value)

        # Set the Units object on the bounds
        if self.isbounded and hasattr(self.bounds, 'Units'):
            self.bounds.Units = value.copy()
    #--- End: def
    
    @Units.deleter
    def Units(self):
        Variable.Units.fdel(self)
        
        # Delete the Units object from the bounds
        if self.isbounded and hasattr(self.bounds, 'Units'):
            del self.bounds.Units
    #--- End: def

    # ----------------------------------------------------------------
    # CF property: units (a special attribute)
    # ----------------------------------------------------------------
    # DCH possible inconsistency when setting self.Units.units
    @property
    def units(self):
        '''

The units CF property.

This property is a mirror of the units stored in the `Units`
attribute.

**Examples**

>>> c.units = 'degrees_east'
>>> c.units
'degree_east'
>>> del c.units

>>> f.setprop('units', 'days since 2004-06-01')
>>> f.getprop('units')
'days since 2004-06-01'
>>> f.delprop('units')

'''
        return Variable.units.fget(self)
    #--- End: def

    @units.setter
    def units(self, value):
        Variable.units.fset(self, value)

        # Set the units on the bounds        
        if self.isbounded and hasattr(self.bounds, 'Units'):
            self.bounds.units = value 
    #--- End: def
    
    @units.deleter
    def units(self):
        Variable.units.fdel(self)
        
        # Delete the units from the bounds
        if self.isbounded and hasattr(self.bounds, 'Units'):
            del self.bounds.units
    #--- End: def

    # ----------------------------------------------------------------
    # CF property: axis
    # ----------------------------------------------------------------
    @property
    def axis(self):
        '''

The axis CF property.

**Examples**

>>> c.axis = 'Y'
>>> c.axis
'Y'
>>> del c.axis

>>> f.setprop('axis', 'T')
>>> f.getprop('axis')
'T'
>>> f.delprop('axis')

'''
        return self.getprop('axis')
    #--- End: def
    @axis.setter
    def axis(self, value): self.setprop('axis', value)
    @axis.deleter
    def axis(self):        self.delprop('axis')

    # ----------------------------------------------------------------
    # CF property: positive (a simple attribute)
    # ----------------------------------------------------------------
    @property
    def positive(self):
        '''

The positive CF property.

**Examples**

>>> c.positive = 'up'
>>> c.positive
'up'
>>> del c.positive

>>> f.setprop('positive', 'down')
>>> f.getprop('positive')
'down'
>>> f.delprop('positive')

'''
        return self.getprop('positive')
    #--- End: def

    @positive.setter
    def positive(self, value): self.setprop('positive', value)
    @positive.deleter
    def positive(self):        self.delprop('positive')

    # ----------------------------------------------------------------
    # CF property: calendar (a special attribute)
    # ----------------------------------------------------------------
    @property
    def calendar(self):
        '''
The calendar CF property.

This property is a mirror of the calendar stored in the `Units`
attribute.

**Examples**

>>> c.calendar = 'noleap'
>>> c.calendar
'noleap'
>>> del c.calendar

>>> f.setprop('calendar', 'proleptic_gregorian')
>>> f.getprop('calendar')
'proleptic_gregorian'
>>> f.delprop('calendar')

'''
        return Variable.calendar.fget(self)
    #--- End: def

    @calendar.setter
    def calendar(self, value):
        Variable.calendar.fset(self, value)
        
        # Set the calendar on the bounds
        if self.isbounded and hasattr(self.bounds, 'Units'):
            self.bounds.calendar = value
    #--- End: def

    @calendar.deleter
    def calendar(self):
        Variable.calendar.fdel(self)
        
        # Delete the calendar from the bounds
        if self.isbounded and hasattr(self.bounds, 'Units'):
            del self.bounds.calendar
    #--- End: def
   
    # ----------------------------------------------------------------
    # Attribute: bounds (a special attribute)
    # ----------------------------------------------------------------
    @property
    def bounds(self):
        '''

The CoordinateBounds object containing the data array's cell bounds.

**Examples**

>>> c.bounds
<CF CoordinateBounds: >

'''
        return self._get_special_attr('bounds')
    #--- End: def
    @bounds.setter
    def bounds(self, value): self._set_special_attr('bounds', value)
    @bounds.deleter
    def bounds(self):        self._del_special_attr('bounds')

    # ----------------------------------------------------------------
    # CF property: climatology (a special attribute)
    # ----------------------------------------------------------------
    @property
    def climatology(self):
        '''

Indicator for the coordinate array's bounds representing
climatological time intervals.

If not set then bounds are assumed to not represent climatological
time intervals.

**Examples**

>>> c.climatology = True
>>> c.climatology
True
>>> del c.climatology

'''
        return self._get_special_attr('climatology')
    #--- End: def
    @climatology.setter
    def climatology(self, value): self._set_special_attr('climatology', value)
    @climatology.deleter
    def climatology(self):        self._del_special_attr('climatology')
   
    # ----------------------------------------------------------------
    # Attribute: isbounded
    # ----------------------------------------------------------------
    @property
    def isbounded(self):
        '''

True if and only if the coordiante has cell bounds.

**Examples**

>>> if c.isbounded:
...    print c.bounds

'''
        return hasattr(self, 'bounds')
    #--- End: def

    # ----------------------------------------------------------------
    # Attribute: transforms
    # ----------------------------------------------------------------
    @property
    def transforms(self):
        '''

Pointer to the coordinate's transforms.

'''
        return self._getter('transforms')
    #--- End: for
    @transforms.setter
    def transforms(self, value): self._setter('transforms', value)
    @transforms.deleter
    def transforms(self):        self._deleter('transforms')

    @property
    def varray(self):
        '''

Return a numpy view of the data.

Making changes to elements of the returned view changes the underlying
data. Refer to :obj:`numpy.ndarray.view`.
    
**Examples**

>>> a = c.varray
>>> type(a)
<type 'numpy.ndarray'>
>>> a
array([0, 1, 2, 3, 4])
>>> a[0] = 999
>>> c.varray
array([999, 1, 2, 3, 4])

'''
        if self.isbounded:
            self.bounds.varray
       
        return super(Coordinate, self).varray
    #--- End: if

    def clip(self, a_min, a_max, units=None):
        '''

Clip (limit) the values in the data array and its bounds in place.

Given an interval, values outside the interval are clipped to the
interval edges.

Parameters :
 
    a_min : scalar

    a_max : scalar

    units : str or Units

:Returns: 

    None

**Examples**

'''
        self.Data.clip(a_min, a_max, units=units)
        
        if self.isbounded:
            self.bounds.Data.clip(a_min, a_max, units=units)
    #--- End: def
  
    def chunk(self, chunksize=None, extra_boundaries=None, pdim=None):
        '''
'''         
        extra_boundaries, pdim = super(Coordinate, self).chunk(chunksize, 
                                                               extra_boundaries,
                                                               pdim)
        if not extra_boundaries:
            return None, None
        
        if self.isbounded:
            self.bounds.chunk(None, extra_boundaries, pdim)

        return extra_boundaries, pdim
    #--- End: def

    def contiguous(self, overlap=True):
        '''

Return True if a coordinate is contiguous.

A coordinate is contiguous if its cell boundaries match up, or
overlap, with the boundaries of adjacent cells.

In general, it is only possible for 1 or 0 dimensional coordinates
with bounds to be contiguous, but size 1 coordinates with any number
of dimensions are always contiguous.

An exception occurs if the coordinate is multdimensional and has more
than one element.

:Parameters:

    overlap : bool, optional    
        If False then overlapping cell boundaries are not considered
        contiguous. By default cell boundaries are considered
        contiguous.

:Returns:

    out : bool
        Whether or not the coordinate is contiguous.

:Raises:

    ValueError :
        If the coordinate has more than one dimension.

**Examples**

>>> c.isbounded
False
>>> c.contiguous()
False

>>> print c.bounds[:, 0]
[  0.5   1.5   2.5   3.5 ]
>>> print c.bounds[:, 1]
[  1.5   2.5   3.5   4.5 ]
>>> c.contiuous()
True

>>> print c.bounds[:, 0]
[  0.5   1.5   2.5   3.5 ]
>>> print c.bounds[:, 1]
[  2.5   3.5   4.5   5.5 ]
>>> c.contiuous()
True
>>> c.contiuous(overlap=False)
False

'''
        if self.size == 1:
            return True

        if self.ndim > 1:
            raise ValueError(
                "Can't tell if a multidimensional coordinate is contiguous")

        if not self.isbounded:
            return False    

        bounds = self.bounds.Data
        bounds.to_memory()

        if overlap:
            return (bounds[1:, 0] <= bounds[:-1, 1]).all()
        else:
            return bounds[1:, 0].equals(bounds[:-1, 1])
    #--- End: def

    def cos(self):
        '''

Take the trigonometric cosine of the data array and bounds in place.

Units are accounted for in the calcualtion, so that the the cosine of
90 degrees_east is 0.0, as is the sine of 1.57079632 radians. If the
units are not equivalent to radians (such as Kelvin) then they are
treated as if they were radians.

The Units are changed to '1' (nondimensionsal).

:Returns: 

    None

**Examples**

>>> c.Units
<CF Units: degrees_east>
>>> print c.array
[[-90 0 90 --]]
>>> c.cos()
>>> c.Units
<CF Units: 1>
>>> print c.array
[[0.0 1.0 0.0 --]]

>>> c.Units
<CF Units: m s-1>
>>> print c.array
[[1 2 3 --]]
>>> c.cos()
>>> c.Units
<CF Units: 1>
>>> print c.array
[[0.540302305868 -0.416146836547 -0.9899924966 --]]

'''
        super(Coordinate, self).cos()

        if self.isbounded:
            self.bounds.cos()
    #--- End: def

    def copy(self, _omit_Data=False):  
        '''
        
Return a deep copy.

Equivalent to ``copy.deepcopy(c)``.

:Returns:

    out :
        The deep copy.

**Examples**

>>> d = c.copy()

'''
        new = super(Coordinate, self).copy(_omit_Data=_omit_Data,
                                           _omit_special=('bounds',))

        if self.isbounded:
            new.bounds = self.bounds.copy(_omit_Data=_omit_Data)

        return new
    #--- End: def

    def dump(self, id=None, omit=()): 
        '''

Return a string containing a full description of the coordinate.

:Parameters:

    id: str, optional
       Set the common prefix of variable component names. By default
       the instance's class name is used.

    omit : sequence of strs
        Omit the given CF properties from the description.

:Returns:

    out : str
        A string containing the description.

**Examples**

>>> x = c.dump()
>>> print c.dump()
>>> print c.dump(id='time_coord')
>>> print c.dump(omit=('long_name',))

'''
        if id is None:
            id = self.__class__.__name__       

        default = getattr(self, 'ncvar', '')

        string = ['%s coordinate' % self.name(default=default, long_name=True)]
        string.append(''.ljust(len(string[0]), '-'))
        
        string.append(super(Coordinate, self).dump(id=id, omit=omit+('bounds',
                                                                     'transforms',
                                                                     )))

        if self.isbounded:
           string.append(self.bounds.dump(id=id+'.bounds', omit=omit+('bounds',
                                                                      'Units')))

        if hasattr(self, 'transforms'):
            string.append('%s.transforms = %s\n' % (id,
                                                    repr(self.transforms)))
            
        return '\n'.join(string)
    #--- End: def

    def _insert_data(self, other, indices,
                     PDim, PDim_direction, dim_name_map):
        '''
'''
        # Insert the coordinate's data
        super(Coordinate, self)._insert_data(other, indices, 
                                             PDim, PDim_direction,
                                             dim_name_map)
        
        # Insert the coordinate's bounds, if it has any
        if self.isbounded:
            self.bounds._insert_data(other.bounds, indices,
                                     PDim, PDim_direction, dim_name_map)
        #--- End: if

    #--- End: def

    def expand_dims(self, axis, dim, direction):
        '''
axis is an integer
dim is a string
direction is a boolean

'''
        # Expand the requested dimensions in the coordinate's data
        super(Coordinate, self).expand_dims(axis, dim, direction)

        # Expand the requested dimensions in the coordinate's bounds,
        # if it has any
        if self.isbounded:
            if axis < 0:
                axis += self.ndims

            self.bounds.expand_dims(axis, dim, direction)
    #--- End: def

    def flip(self, axes=None):
        '''

Flip dimensions of the data array and bounds in place.

The trailing dimension of the bounds is flipped if and only if the
coordinate is 1 or 0 dimensional.

:Parameters:

    axes : int or sequence of ints
        Flip the dimensions whose positions are given. By default all
        dimensions are flipped.

:Returns:

    out : list of ints
        The axes which were flipped, in arbitrary order.

**Examples**

>>> c.flip()
>>> c.flip(1)

>>> d = c.subspace[::-1, :, ::-1, :]
>>> c.flip([2, 0]).equals(d)
True

'''  
        # Flip the requested dimensions in the coordinate's data
        axes = super(Coordinate, self).flip(axes)

        # ------------------------------------------------------------
        # Flip the requested dimensions in the coordinate's bounds, if
        # it has any.
        #
        # As per section 7.1 in the CF conventions: i) if the
        # coordinate is 0 or 1 dimensional then flip all dimensions
        # (including the the trailing size 2 dimension); ii) if the
        # coordinate has 2 or more dimensions then do not flip the
        # trailing dimension.
        # ------------------------------------------------------------
        if self.isbounded:
            if self.bounds.ndim <= 2:
                axes = None   # None means flip all dimensions
            self.bounds.flip(axes)
    #--- End: def

    def sin(self):
        '''

Take the trigonometric sine of the data array and bounds in place.

Units are accounted for in the calculation. For example, the the sine
of 90 degrees_east is 1.0, as is the sine of 1.57079632 radians. If
the units are not equivalent to radians (such as Kelvin) then they are
treated as if they were radians.

The Units are changed to '1' (nondimensionsal).

:Returns:

    None

**Examples**

>>> c.Units
<CF Units: degrees_north>
>>> print c.array
[[-90 0 90 --]]
>>> c.sin()
>>> c.Units
<CF Units: 1>
>>> print c.array
[[-1.0 0.0 1.0 --]]

>>> c.Units
<CF Units: m s-1>
>>> print c.array
[[1 2 3 --]]
>>> c.sin()
>>> c.Units
<CF Units: 1>
>>> print c.array
[[0.841470984808 0.909297426826 0.14112000806 --]]

'''
        super(Coordinate, self).sin()

        if self.isbounded:
            self.bounds.sin()
    #--- End: def

    def squeeze(self, axes=None):
        '''

Remove size 1 dimensions from the data array and bounds in place.

:Parameters:

    axes : int or sequence of ints, optional
        The size 1 axes to remove. By default, all size 1 axes are
        removed. Size 1 axes for removal may be identified by the
        integer positions of dimensions in the data array.

:Returns:

    None

**Examples**

>>> c.squeeze()
>>> c.squeeze(1)
>>> c.squeeze([1, 2])

'''
        # Squeeze the requested dimensions in the coordinate's data
        super(Coordinate, self).squeeze(axes)

        # Squeeze the requested dimensions in the coordinate's bounds,
        # if it has any
        if self.isbounded:
            self.bounds.squeeze(axes)
    #--- End: def

    def transpose(self, axes=None):
        '''

Permute the dimensions of the data array and bounds in place.

:Parameters:

    axes : sequence of ints, optional
        The new order of the data array. By default, reverse the
        dimensions' order, otherwise the axes are permuted according
        to the values given. The values of the sequence comprise the
        integer positions of the dimensions in the data array in the
        desired order.

:Returns:

    None

**Examples**

>>> c.transpose()
>>> c.ndim
3
>>> c.transpose([1, 2, 0])

'''
        # Transpose the coordinate's data
        super(Coordinate, self).transpose(axes=axes)

        # Tran-pose the coordinate's bounds, if it has any.
        if self.isbounded:
            axes = list(axes)
            axes.append(self.ndim)
            self.bounds.transpose(axes=axes)
    #--- End: def

#--- End: class


# ====================================================================
#
# SubspaceCoordinate object
#
# ====================================================================

class SubspaceCoordinate(SubspaceVariable):

    __slots__ = []

    def __getitem__(self, indices):
        '''
x.__getitem__(index) <==> x[index]

'''
        coord = self.variable

        # Copy the coordinate
        new = coord.copy(_omit_Data=True)

        # Parse the index (so that it's ok for appending the bounds
        # index if required)
        indices = parse_indices(coord, indices)
    
        new.Data = coord.Data[tuple(indices)]

        # Subspace the bounds, if there are any
        if coord.isbounded:
            if coord.ndim <= 1:
                index = indices[0]
                if coord.size == 1:
                    if isinstance(index, slice) and index.step < 0:
                        # This 0- or 1-d, size 1 coordinate has been
                        # reversed so reverse its bounds (as per 7.1
                        # of the conventions).
                        indices.append(slice(None, None, -1))
                        
                elif coord.ndim == 1:
                    if isinstance(index, slice):
                        if index.step < 0:
                            # This 1-d, size > 1 coordinate has been
                            # reversed, so reverse its bounds (as per
                            # 7.1 of the conventions).
                            indices.append(slice(None, None, -1))
                    elif index[-1] < index[0]:
                        # This 1-d, size > 1 coordinate has been
                        # reversed, so reverse its bounds (as per 7.1
                        # of the conventions).
                        indices.append(slice(None, None, -1))
            #--- End: if

            new.bounds = coord.bounds.subspace[tuple(indices)]
        #--- End: if

        # Return the new coordinate
        return new
    #--- End: def

#--- End: class
